﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace ArtheaEngine
{
    public static class Util
    {
        static Util()
        {
            Randomizer = new Random();
        }

        public static Random Randomizer { get; private set; }

        public static bool IsEmail(string inputEmail)
        {
            inputEmail = inputEmail ?? "";
            const string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
                                    @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                                    @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
            var re = new Regex(strRegex);
            return re.IsMatch(inputEmail);
        }

        /// <summary>
        /// Gets the length of a number of lines.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <param name="count">The number of lines to count.</param>
        /// <returns></returns>
        public static int GetLineLength(this string str, int count)
        {
            int length = str.IndexOf(Environment.NewLine);
            int i = 0;
            int point = -1;

            while (length != -1)
            {
                if (++i >= count)
                    break;

                point = length + Environment.NewLine.Length;

                length = str.IndexOf(Environment.NewLine, point);
            }

            return point;
        }

        /// <summary>
        /// Determines whether the specified STR has a line.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <returns>
        /// 	<c>true</c> if the specified STR has a line; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsLine(this string str)
        {
            return str.Length > 0 && str.EndsWith(Environment.NewLine);
        }

        public static int CountTextInLines(this string str, int count)
        {
            int length = str.IndexOf(Environment.NewLine);
            int i = 0;
            int point = -1;

            while (length != -1)
            {
                if (++i >= count)
                    break;

                point = length + Environment.NewLine.Length;

                length = str.IndexOf(Environment.NewLine, point);
            }

            return point;
        }

        /// <summary>
        /// Joins the specified separator.
        /// </summary>
        /// <param name="separator">The separator.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static string JoinWith(this String[] value, string separator)
        {
            var newValue = new string[value.Length];
            value.CopyTo(newValue, 0);
            return String.Join(separator, newValue);
        }


        /// <summary>
        /// Makes the readable.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <returns></returns>
        public static string MakeReadable(this string str)
        {
            var buf = new StringBuilder();
            CharEnumerator c = str.GetEnumerator();

            if (!c.MoveNext())
                return str;

            buf.Append(char.ToUpper(c.Current));

            while (c.MoveNext())
            {
                if (char.IsUpper(c.Current))
                {
                    buf.Append(" ");
                }
                buf.Append(c.Current);
            }

            return buf.ToString();
        }

        /// <summary>
        /// Finds an argument prefixed by a multiplier (7*argument)
        /// </summary>
        /// <param name="arg">The arg.</param>
        /// <param name="str">the string to operate on</param>
        /// <returns></returns>
        public static int GetMultiArg(this string str, out string arg)
        {
            return str.GetNumberedArg(out arg, '*');
        }

        /// <summary>
        /// Finds an argument prefixed by an index (7.argument)
        /// </summary>
        /// <param name="str">the string to operate on</param>
        /// <param name="arg">The arg.</param>
        /// <returns></returns>
        public static int GetNumberedArg(this string str, out string arg)
        {
            return str.GetNumberedArg(out arg, '.');
        }

        private static int GetNumberedArg(this string mString, out string arg, char c)
        {
            int index = mString.IndexOf(c);

            if (index == -1)
            {
                arg = mString;
                return 1;
            }

            int number;

            int.TryParse(mString.Substring(0, index), out number);

            arg = mString.Substring(index + 1);

            return number;
        }

        /// <summary>
        /// Puts the first letter in upper case and the rest in lower case
        /// </summary>
        /// <returns>a captialized string</returns>
        public static string Capitalize(this string mString, bool tolower)
        {
            if (string.IsNullOrEmpty(mString))
            {
                return mString;
            }

            char firstLetter = !char.IsUpper(mString[0]) ? char.ToUpper(mString[0]) : mString[0];

            if (tolower)
                return firstLetter + mString.Substring(1).ToLower();


            return firstLetter + mString.Substring(1);
        }

        public static string Capitalize(this string mString)
        {
            return mString.Capitalize(true);
        }


        /// <summary>
        /// Gets the lines.
        /// </summary>
        /// <returns></returns>
        public static string[] GetLines(this string mString)
        {
            if (mString == null) return new string[0];
            return mString.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
        }

        /// <summary>
        /// Checks if a string is a number
        /// </summary>
        /// <returns>true if the string is a number</returns>
        public static bool IsNumber(this string mString)
        {
            if (string.IsNullOrEmpty(mString))
                return false;

            for (CharEnumerator ch = mString.GetEnumerator(); ch.MoveNext();)
            {
                if (!char.IsDigit(ch.Current))
                    return false;
            }
            return true;
        }

        public static bool DeepCompare(this byte[] orig, byte[] passwd)
        {
            if (orig.Length != passwd.Length)
                return false;

            for (int i = 0; i < orig.Length; i++)
            {
                if (orig[i] != passwd[i])
                {
                    return false;
                }
            }
            return true;
        }

        public static bool And(this long value, long bit)
        {
            return (value & bit) != 0;
        }

        public static bool And(this int value, int bit)
        {
            return (value & bit) != 0;
        }

        public static bool HasWord(this string value, string word)
        {
            var arg = new Argument(value);

            while (!arg.IsEmpty())
            {
                string check = arg.FirstArg();

                if (check.Equals(word, StringComparison.CurrentCultureIgnoreCase))
                    return true;
            }

            return false;
        }

        public static string StripColor(this string mString)
        {
            return Regex.Replace(mString, Color.Code +
                                          "[!@#$%]*[GRCBYMDWNgrcbymdwxn?*" + Color.Code + "]", string.Empty);
        }

        public static int DisplayLength(this string str)
        {
            return str.StripColor().Length;
        }

        public static Character FindByName(this IEnumerable<Character> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;
            foreach (Character ch in list)
            {
                if (ch.Name.HasWord(name))
                    return ch;
            }
            return null;
        }

        public static Object FindByName(this IEnumerable<Object> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;
            foreach (Object obj in list)
            {
                if (obj.Name.HasWord(name))
                    return obj;
            }
            return null;
        }

        public static PlayerRace FindByName(this IEnumerable<PlayerRace> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;
            foreach (PlayerRace r in list)
            {
                if (r.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase))
                    return r;
            }
            return null;
        }

        public static Race FindByName(this IEnumerable<Race> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;

            foreach (Race r in list)
            {
                if (r.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase))
                    return r;
            }
            return null;
        }

        public static ClassType FindByName(this IEnumerable<ClassType> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;
            foreach (ClassType c in list)
            {
                if (c.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase))
                    return c;
            }
            return null;
        }

        public static Spell FindSpellByName(this IEnumerable<Ability> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;

            foreach (Ability a in list)
            {
                if (!(a is Spell))
                    continue;

                if (a.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase))
                    return a as Spell;
            }
            return null;
        }

        public static Skill FindSkillByName(this IEnumerable<Ability> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;

            foreach (Ability a in list)
            {
                if (!(a is Skill)) continue;

                if (a.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase))
                    return a as Skill;
            }
            return null;
        }

        public static Ability FindByName(this IEnumerable<Ability> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return null;

            foreach (Ability a in list)
            {
                if (a.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase))
                    return a as Skill;
            }
            return null;
        }

        public static short Get(this ICollection<CharAbility> list, string name)
        {
            if (string.IsNullOrEmpty(name)) return -1;
            foreach (CharAbility ca in list)
            {
                if (ca.Name == name)
                {
                    return ca.Level;
                }
            }
            return -1;
        }
    }
}